package server.model.solver.maze.algorithms.bfs;

import java.util.ArrayList;
import java.util.Comparator;

import server.model.solver.maze.algorithms.*;

public class BFS extends AbsSearcher {
	protected IDomain domain;
	protected IDistance h;
	
	public BFS(IDomain domain, IDistance h) {
		super(new Comparator<State>()
		{
			public int compare (State state1, State state2) {
				return ((int)state1.getF() - (int)state2.getF() * (-1));
			}
		});
		
		this.domain = domain;
		this.h = h;
	}
	
	public IDomain getDomain() {
		return domain;
	}
	
	public void setDomain(IDomain domain) {
		this.domain = domain;
	}
	
	public ArrayList<IAction> search(State start, State goal) {
		start.setG(0);
		addToOpenList(start);
		start.setF(h.getDistance(start,goal));
			
		while (!(isEmptyOpenList())) {
			State q = pollFromOpenList();

			if (q.getState().equals(goal.getState())) {
				return reconstructPath(q, start);
			}
			
			addToCloseList(q);
			
			for (IAction action : domain.getActions(q)) {
				State qTag = action.doAction(q);
				
				if (containsInCloseList(qTag)) {
					continue;
				}
				
				if (!containsInOpenList(qTag)) {
					qTag.setCameFromState(q);
					qTag.setCameFromAction(action);
					qTag.setF(h.getDistance(qTag, goal));
					addToOpenList(qTag);
				}
			}
		}
		return new ArrayList<IAction>();
	}
	
	private ArrayList<IAction> reconstructPath(State goal, State start) {
			if (goal.getCameFromState() != null) {
				ArrayList<IAction> path = reconstructPath(goal.getCameFromState(),start);
				path.add(goal.getCameFromAction());
				return path;
			}	
			return new ArrayList<IAction>();
		}
	
	public int getNumOfEvaluatedNodes() {
		return 0;
	}
}
